package org.urchr.beorganized.dao;

import java.util.ArrayList;
import java.util.List;

import org.hibernate.HibernateException;
import org.urchr.beorganized.dao.errors.DBErrorException;
import org.urchr.beorganized.dao.errors.InvalidUserException;
import org.urchr.beorganized.dao.errors.NoPermissionException;
import org.urchr.beorganized.dao.tables.Note;
import org.urchr.beorganized.dao.tables.Permission;
import org.urchr.beorganized.dao.tables.User;
import org.urchr.web.db.DBSession;
import org.w3c.dom.Element;
import org.w3c.dom.Node;

public class PermissionsDAO {
	
	public enum PermissionType {VIEW, CREATE, EDIT, DELETE};
	
	public static void removePermission(int userID, int noteID, int permissionID)
				throws DBErrorException, NoPermissionException{
		DBSession session = new DBSession();
		try {
			Note note = (Note) session.get(Note.class, noteID);
			if(note.getUser().getId()!=userID)
				throw new NoPermissionException();
			Permission permission = (Permission) session.get(Permission.class, permissionID);
			
			if(permission.getNote().getId()!=noteID || permission.getUser().getId()==userID)
				throw new NoPermissionException();
			session.begin();
			session.getSession().delete(permission);
			session.commit();
			
		} catch (HibernateException e) {
			e.printStackTrace();
			session.rollback();
			throw new DBErrorException();
		} finally {
			session.close();
		}
		
	}
	
	public static void addPermission(int userID, int noteID, String userName, 
			boolean add, boolean edit, boolean delete)
				throws DBErrorException, NoPermissionException, InvalidUserException{
		DBSession session = new DBSession();
		try {
			Note note = (Note) session.get(Note.class, noteID);
			if(note.getUser().getId()!=userID)
				throw new NoPermissionException();
			List<User> users = session.createQuery("from User where login=:login").
					setString("login", userName).
				list();
			if(users.size()!=1)
				throw new InvalidUserException();
			if(users.get(0).getId()==userID)
				throw new InvalidUserException();
			List<Permission> oldPerm = session.createQuery("from Permission " +
					"where note=:note and user=:user").
					setEntity("note", note).
					setEntity("user", users.get(0)).
				list();
			if(oldPerm.size()>0)
				throw new InvalidUserException();
			session.begin();
			Permission permission = new Permission();
			permission.setUser(users.get(0));
			permission.setNote(note);
			
			permission.setAllowCreate(add?1:0);
			permission.setAllowEdit(edit?1:0);
			permission.setAllowDelete(delete?1:0);
			
			session.save(permission);
			session.commit();
			
		} catch (HibernateException e) {
			e.printStackTrace();
			session.rollback();
			throw new DBErrorException();
		} finally {
			session.close();
		}
		
	}
	
	public static List<Permission> getPermissions(int userID, int noteID) throws DBErrorException{
		DBSession session = new DBSession();
		try {
			Note note = (Note) session.get(Note.class, noteID);
			List<Permission> result = session.createQuery("from Permission " +
					"where note=:note order by id").
					setEntity("note", note).
//					setEntity("user", UsersDAO.getCurrent(session, userID)).
				list();
			for (int i = 0; i < result.size(); i++) {
				if(result.get(i).getUser().getId()==userID){
					result.remove(i);
					return result;
				}
			}
			return result;
		} catch (Exception e) {
			// TODO: handle exception
			throw new DBErrorException();
		}		
	}
	
	public static List<Permission> getPermissions(DBSession session, int userID){
		List<Permission> perms = session.getSession().createQuery("from Permission p " +
					"where p.user=:user and p.note.archived=0 order by p.id").
					setEntity("user", UsersDAO.getCurrent(session, userID)).setCacheable(true).list();
		return perms;
	}
	
	public static Permission getPermission(int userID, Note note)throws DBErrorException{
		DBSession session = new DBSession();
		try {
			return getPermission(session, userID, note);
		} catch (Exception e) {
			// TODO: handle exception
			throw new DBErrorException();
		}
	}
	
	public static Permission getPermission(DBSession session, int userID, Note note){
		if(note==null)
			return null;
//		ctx.log("getPermission: note = "+note.getName());
		for (Permission perm : getPermissions(session, userID)) {
//			ctx.log("p: "+perm.getNote().getName()+", user = "+perm.getUser().getLogin()+
//					":"+(note.getLeft()>=perm.getNote().getLeft())+":"+
//					(note.getRight()<=perm.getNote().getRight())+":"+
//					(note.getUser().getId()==perm.getNote().getUser().getId()));
			
			if(note.getLeft()>=perm.getNote().getLeft() && 
					note.getRight()<=perm.getNote().getRight() &&
					note.getUser().getId()==perm.getNote().getUser().getId()){
				return perm;
			}
		}
		return null;
	}
	
	public static PermissionObject getPermissionObject(int userID, Note note) throws DBErrorException{
		PermissionObject object = new PermissionObject();
		DBSession session = new DBSession();
		try {
			for (Permission perm : getPermissions(session, userID)) {
				if(note.getLeft()>=perm.getNote().getLeft() && 
						note.getRight()<=perm.getNote().getRight() &&
						note.getUser().getId()==perm.getNote().getUser().getId()){
					object.setView(true);
					if(perm.getAllowCreate()>0)
						object.setCreate(true);
					if(perm.getAllowEdit()>0)
						object.setEdit(true);
					if(perm.getAllowDelete()>0)
						object.setDelete(true);					
				}
			}			
		} catch (HibernateException e) {
			throw new DBErrorException();
		} finally {
			session.close();
		}
		return object;
	}
	
	public static boolean hasPermission(DBSession session, int userID, Note note, PermissionType type){
		try {
			for (Permission perm : getPermissions(session, userID)) {
				if(note.getLeft()>=perm.getNote().getLeft() && 
						note.getRight()<=perm.getNote().getRight() &&
						note.getUser().getId()==perm.getNote().getUser().getId()){
					switch (type) {
						case VIEW:
							return true;
						case CREATE:
							if(perm.getAllowCreate()>0)
								return true;
							break;
						case EDIT:
							if(perm.getAllowEdit()>0)
								return true;
							break;
						case DELETE:
							if(perm.getAllowDelete()>0)
								return true;
							break;
					}				
				}
			}
		} catch (Exception e) {
		}
		return false;
	}
}
